package model.environment;

import java.util.Date;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

import model.Item;
import model.XML;

import org.jdom.Document;
import org.jdom.JDOMException;

public class Items {
	private static ReentrantLock itemLock = new ReentrantLock();
	private static List<Item> items = null;
	private static long lastUpdate = new Date().getTime();
	
	/**
	 * Gets all items from the shop with OUR_SHOP_ID as id.
	 * @return A list of items.
	 */
	public static List<Item> getItems()
	{
		try {
			itemLock.lock();
			
			long timeSinceLastUpdate = new Date().getTime() - lastUpdate;
			
			if (items == null || timeSinceLastUpdate > StaticInfo.UPDATE_TIMEOUT)
			{
				try {
					items = XML.getShopItems(StaticInfo.OUR_SHOP_ID);
					lastUpdate = new Date().getTime();
				}
				catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		} finally {
			itemLock.unlock();
		}
		
		return items;
	}
	
	/**
	 * Gets the items from a specific shop. This has no cache as opposed to getItems() which gets the items from our shop.
	 * This is used in showCustomerSales.jsp for example.
	 * @param shopID The shop's id.
	 * @return A list of items from the specified shop.
	 */
	public static List<Item> getItems(int shopID) {
		try {
			return XML.getShopItems(shopID);
		}
		catch (Exception e) {
			return null;
		}
	}
	
	/**
	 * Gets an item from the shop with OUR_SHOP_ID as ID and the specified item id.
	 * @param id The item's id.
	 * @return An item with the specified id.
	 */
	public static Item getItem(int id) {
		Item result = null;
		
		try {
			itemLock.lock();
			
			List<Item> items = getItems();
			
			for (Item i : items) {
				if (i.getItemID() == id) {
					result = i;
					break;
				}
			}
		} finally {
			itemLock.unlock();
		}
		
		return result;
	}
	
	/**
	 * Gets a specific item from a specific shop.
	 * This is used in showCustomerSales.jsp for example.
	 * @param itemID The item's ID.
	 * @param shopID The shop's ID.
	 * @return An item.
	 */
	public static Item getItem(int itemID, int shopID) {
		Item result = null;
		
		List<Item> items = getItems(shopID);
		
		for (Item i : items) {
			if (i.getItemID() == itemID) {
				result = i;
				break;
			}
		}
		
		return result;
	}
	
	/**
	 * Forces the item list to update the next time getItems() is called.
	 */
	public static void resetItemsList() {
		items = null;
	}
	
	/**
	 * Creates a new item returning the new item's ID or -1.
	 * @param name The new item's name.
	 * @return The new item's ID or -1.
	 */
	private static int createItem(String name) {
		if (name == null || name.equals("")) {
			return -1;
		}
		
		Document createItemDoc = XML.createCreateItemElement(name, StaticInfo.SHOP_KEY);
		String createItemURL = "http://services.brics.dk/java4/cloud/createItem";
		
		try {
			Document response = XML.postXML(createItemDoc, createItemURL);
			return XML.getCreatedItemID(response);
		} catch (Exception e) {
			return -1;
		}
	}
	
	/**
	 * Adjusts an items stock.
	 * @param itemID The item's ID.
	 * @param stockAdjustment The stock adjustment (+-).
	 * @return StaticInfo.Message.ADJUST_STOCK_OK or StaticInfo.Message.ADJUST_STOCK_FAILED.
	 */
	private static StaticInfo.Message adjustItemStock(int itemID, int stockAdjustment) {
		String stockAdjustURL = "http://services.brics.dk/java4/cloud/adjustItemStock";
		Document adjustItemStockDoc = XML.createAdjustItemStockElement(StaticInfo.SHOP_KEY, itemID, stockAdjustment);
		try {
			XML.postXML(adjustItemStockDoc, stockAdjustURL);
			return StaticInfo.Message.ADJUST_STOCK_OK;
		} catch (JDOMException e) {
			// Gives no response. No response, means no valid XML = JDOMException from the SAXBuilder.
			return StaticInfo.Message.ADJUST_STOCK_OK;
		} catch (Exception e) {
			// Gives no response but throws a 400 (bad request) if anything goes wrong.
			return StaticInfo.Message.ADJUST_STOCK_FAILED;
		}
	}
	
	/**
	 * Modifies an item, creating it if necessary.
	 * @param item The item. The item with item.getItemID() will be updated.
	 * 			   If the item is a new item then originally item.getItemID() must be = -1,
	 * 			   however item.getItemID() will be updated to the new item's new ID.
	 * @return A StaticInfo.Message status message. CREATE_ITEM_FAILED. EDIT_ITEM_FAILED. ADJUST_STOCK_FAILED. EDIT_ITEM_OK.
	 */
	public static StaticInfo.Message modifyItem(Item item) {
		int itemID = item.getItemID();
		String itemName = item.getItemName();
		int newStock = item.getItemStock();
		int itemPrice = item.getItemPrice();
		String itemDescription = item.getItemDescription();
		String itemURL = item.getItemURL();
		
		int oldStock;
		
		if (itemID == -1) {
			// New item. Create it and set its stock to 0.
			itemID = Items.createItem(itemName);
			
			if (itemID == -1) {
				return StaticInfo.Message.CREATE_ITEM_FAILED;
			}
			
			// The stock of this new item is naturally 0.
			oldStock = 0;
			item.setItemID(itemID);
		} else {
			// Get the existing item's current stock.
			Item existingItem = getItem(itemID);
			
			if (existingItem == null) {
				return StaticInfo.Message.EDIT_ITEM_FAILED;
			}
			
			oldStock = existingItem.getItemStock();
		}
		
		int stockAdjustment = newStock - oldStock;
		
		if (stockAdjustment != 0) {
			StaticInfo.Message adjustStockStatus = adjustItemStock(itemID, stockAdjustment);
			if (adjustStockStatus == StaticInfo.Message.ADJUST_STOCK_FAILED) {
				return StaticInfo.Message.ADJUST_STOCK_FAILED;
			}
			
			// Otherwise it's ADJUST_STOCK_OK but we shoudn't return that, just continue.
		}
		
		// Add the XHTML namespace (h:) to the item description's XHTML tags if it is missing.
//		itemDescription = XML.appendNamespaceToItemDescription(itemDescription);
		
		Item modifiedItem = new Item(itemID, itemName, itemURL, itemPrice, newStock, itemDescription);
		
		String modifyItemURL = "http://services.brics.dk/java4/cloud/modifyItem";
		Document editItemDoc = XML.createModifyItemElement(modifiedItem, StaticInfo.SHOP_KEY);
		
		try {
			XML.postXML(editItemDoc, modifyItemURL);
		} catch (JDOMException e) {
			// Gives no response. No response, means no valid XML = JDOMException from the SAXBuilder.
		} catch (Exception e) {
			// /modifyItem gives no response but its pretty safe to assume that if we get an exception, something went wrong.
			return StaticInfo.Message.EDIT_ITEM_FAILED;
		}
		
		return StaticInfo.Message.EDIT_ITEM_OK;
	}
}
